/*      $Id: uri.c,v 1.3 2006/03/16 17:53:09 jfb Exp $    */
/*
 * Copyright (c) 2003 Jean-Francois Brousseau <phrakt@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * Sample URIs that should be parsable:
 *
 *	http://www.example.com/
 *	http://index.html
 *	http://user@www.example.com/
 *	http://user:pwd@www.example.com/
 *	http://www.example.com/somepath/index.html
 *	http://www.example.com:8080/somepath/index.html
 *	http://www.example.com/index.pl?queryarg1=foo&queryarg2=bar
 *	http://index.html#myfragment
 *	/index.html
 *	/my/path/to/script?qarg=foo&oarg=bar
 */

#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <canopy/log.h>
#include <canopy/string.h>

#include "uri.h"
#include "http.h"
#include "private.h"



/*
* http_uri_parse()
*
* Parse a Uniform Resource Identifier (URI) string <uri_str> and fill an
* HTTP URI structure with all the fields on the original string.
* Returns a pointer to the HTTP URI structure on success, or NULL on failure.
*/

http_uri_t*
http_uri_parse(const char *uri_str)
{
	char *sp, *ep;
	http_uri_t *uri;

	if ((uri = malloc(sizeof(*uri))) == NULL) {
		cnp_log(CNP_LOG_ERRNO, "failed to allocate HTTP URI");
		return (NULL);
	}
	memset(uri, 0, sizeof(*uri));

	if ((uri->uri_string = strdup(uri_str)) == NULL) {
		free(uri);
		return (NULL);
	}

	sp = uri->uri_string;

	/* first get rid of fragment and query */
	ep = strchr(uri->uri_string, HTTP_URI_FRAGDELIM);
	if (ep != NULL) {
		*(ep++) = '\0';
		uri->uri_fragment = ep;
	}

	if ((ep = strchr(uri->uri_string, HTTP_URI_QUERYDELIM)) != NULL) {
		/* query is everything after the delimiter */
		*(ep++) = '\0';
		uri->uri_query = ep;
	}

	/* look for a possible scheme */
	if (uri->uri_string[0] != '/') {
		ep = strchr(uri->uri_string, HTTP_URI_SCHEMEDELIM);
		if (ep == NULL) {
			cnp_log(CNP_LOG_ERR,
			    "missing scheme delimiter in URL `%s'",
			    uri_str);
			http_uri_free(uri);
			return (NULL);
		}
		*(ep++) = '\0';

		if ((*ep != '/') || (*(ep + 1) != '/')) {
			cnp_log(CNP_LOG_ERR, "malformed scheme delimiter");
			http_uri_free(uri);
			return (NULL);
		}
		ep += 2;

		uri->uri_scheme = uri->uri_string;
		sp = ep;
	}

	/*
	 * At this point, we have no more scheme, and no trailing
	 * fragment or query parts left.
	 */
	ep = strchr(sp, HTTP_URI_PATHDELIM);
	if (ep != NULL) {
		uri->uri_path = ep;
		/* assume the rest is the host */
		if ((uri->uri_host = strndup(sp, ep - sp)) == NULL) {
		}
	}

	return (uri);
}


/*
* http_uri_format()
*
* Format the contents of HTTP URI structure <uri> into its string
* representation and store the result in <dst>, which is of size <dlen>.
* The resulting string is guaranteed to be NUL-terminated.
* Returns the number of bytes used, or -1 if an error occured.
*/

ssize_t
http_uri_format(http_uri_t *uri, char *dst, size_t dlen)
{
	size_t len = 0;
	char tmp[32];

	snprintf(dst, dlen, "%s://%s", uri->uri_scheme, uri->uri_host);

	if (uri->uri_port != HTTP_PORT) {
		snprintf(tmp, sizeof(tmp), ":%u", uri->uri_port);
		if (strlcat(dst, uri->uri_path, dlen) >= dlen) {
			return (-1);
		}
	}

	if (strlcat(dst, uri->uri_path, dlen) >= dlen) {
		return (-1);
	}

	return (len);
}


/*
* http_uri_free()
*
* Free the URI structure pointed to by <vp> and all internal data.
*/

void
http_uri_free(http_uri_t *uri)
{
	if (uri->uri_string != NULL)
		free(uri->uri_string);

	if (uri->uri_host != NULL)
		free(uri->uri_host);

	free(uri);
}
